package guard_grammar;

import java.io.IOException;
import java.util.LinkedList;

import model.VariableHashTable;
import net.sourceforge.jeval.EvaluationException;
import net.sourceforge.jeval.Evaluator;
import exception.ExtraCharactersException;
import exception.IllegalCharacterSequenceException;
import exception.LessCharactersExeption;
import exception.NoRuleException;
import exception.UninitializedVariableException;

/**
 * @author Zlatka Trajcheska, Marija Petkovska
 * @version 1.0 03.03.2013 
 * 
 * This class has methods that are used for evaluation of the guards (true/false)
 * or evaluation of the updates (filling in the symbol table)
 */
/**
 * @author DarkoLaptop2
 *
 */
public class Evaluation 
{
	
	/**
	 * This method is used for evaluation of the guards. 
	 * 
	 * @param s - the guard of the transition in String form
	 * @return Boolean - the value of the guard
	 * @throws EvaluationException
	 * @throws UninitializedVariableException
	 * @throws IOException
	 * @throws IllegalCharacterSequenceException
	 * @throws LessCharactersExeption
	 * @throws ExtraCharactersException
	 * @throws NoRuleException
	 */
	public static Boolean evaluateGuard(String s,VariableHashTable symbolTable) throws EvaluationException, UninitializedVariableException, IOException, 
												  IllegalCharacterSequenceException, LessCharactersExeption, 
												  ExtraCharactersException, NoRuleException
	{
		//parsing (validating the guard string)
		Parser parser = new Parser(s);
		LinkedList<Token> tokens = null;
		
		try
		{
			parser.parse();
			//the parsing is ok
			tokens = parser.tokens;			
		}
		catch (Exception e)
		{
			//the parsing is not ok
			e.printStackTrace();
		}
		
		
		String expr="";
		String tmp="";
		Integer value = 0;
		
		//constructing the guard expression using the tokens and the symbol table
		for(int i=0;i<tokens.size();i++)
		{
			//if the token is a variable
			if(tokens.get(i).getId().equals("variable"))
			{
				try 
				{
					value = symbolTable.getVariableValue((tokens.get(i).getValue()));
					tmp=value.toString();
				} 

				//uninitialized variable
				catch (Exception e1) 
				{
					throw new UninitializedVariableException();
				}
				
			}
			//if the token is not a variable add its value to the expression string
			else
			{
				tmp=tokens.get(i).getValue();
			}
			expr+=tmp;
		}
			
		//adjusting the boolean operators to JEval
		expr=expr.replace("|", "||");
		expr=expr.replace("&", "&&");
		
		//using JEval to evaluate
		Evaluator e = new Evaluator();
		String b = e.evaluate(expr);
		if(b.equals("1.0"))
		{
			return true;
		}
		else
		{
			return false;
		}
	}
	
	
	
	/**
	 * This method is used for evaluation of the updates and filling in the symbol table. 
	 * @param s - the update of the transition in String form
	 * @throws ExtraCharactersException 
	 * @throws NoRuleException 
	 * @throws LessCharactersExeption 
	 * @throws IllegalCharacterSequenceException 
	 * @throws IOException
	 * @throws EvaluationException
	 * @throws UninitializedVariableException
	 */
	public static LinkedList<String> getVariablesFromUpdate(String s,LinkedList<String> variables) throws IOException, IllegalCharacterSequenceException, LessCharactersExeption, NoRuleException, ExtraCharactersException{
		update_grammar.Parser parser = new update_grammar.Parser(s);
		LinkedList<Token> tokens = null;
			parser.parse();
			//the parsing is ok
			tokens=parser.tokens;
			for(Token token:tokens)
				if(token.getId().equals("variable"))
					if(!variables.contains(token.getValue()))
						variables.add(token.getValue());
			return variables;
	}
	
	
	/**
	 * Method for getting the variable names from a guard, given the current list of the found variables from other guard strings
	 * @param s - guard string
	 * @param variables - variable names from other guards
	 * @return a update list of variable names 
	 * @throws IOException
	 * @throws IllegalCharacterSequenceException
	 * @throws LessCharactersExeption
	 * @throws NoRuleException
	 * @throws ExtraCharactersException
	 */
	public static LinkedList<String> getVariablesFromGuard(String s,LinkedList<String> variables) throws IOException, IllegalCharacterSequenceException, LessCharactersExeption, NoRuleException, ExtraCharactersException{
		Parser parser = new Parser(s);
		LinkedList<Token> tokens = null;
			parser.parse();
			//the parsing is ok
			tokens=parser.tokens;
			for(Token token:tokens)
				if(token.getId().equals("variable"))
					if(!variables.contains(token.getValue()))
						variables.add(token.getValue());
			return variables;
	}
	
	
	/**
	 * This method is used for evaluation of the update String given the values of all of the variables
	 * @param s - the update string
	 * @param symbolTable - the table of all the variables with their current value
	 * @throws IOException
	 * @throws EvaluationException
	 * @throws UninitializedVariableException
	 */
	public static void evaluateUpdate(String s,VariableHashTable symbolTable) throws IOException, EvaluationException, UninitializedVariableException
	{
		LinkedList<Token> tokens = null;
		
		//parsing (validating) the update string
		update_grammar.Parser parser = new update_grammar.Parser(s);
		try
		{
			parser.parse();
			//the parsing is ok
			tokens=parser.tokens;
		}
		catch(Exception e1)
		{
			//the parsing is not ok
			e1.printStackTrace();
		}
		
		//updating the variables values
		String expr="";
		for(int i=0;i<tokens.size();i++)
		{
			//finding the assignment operator =
			if(tokens.get(i).getId().equals("="))
			{
				String promenliva = tokens.get(i-1).getValue();
				
				i++;
				
				//creating the expression string that should be 
				//evaluated and used for the variable value
				//the updates are separated by ";"
				while(!tokens.get(i).getId().equals(";"))
				{
					//if the token is a variable look it up in the symbol table
					if(tokens.get(i).getId().equals("variable"))
					{
						int tmp;
						try 
						{	
							tmp = symbolTable.getVariableValue((tokens.get(i).getValue()));
						} 
						//uninitialized variable
						catch (Exception e1) 
						{
							throw new UninitializedVariableException();
						}
						expr += tmp;
					}
					//if it's a constant add it to the expression
					else
					{
						expr+=tokens.get(i).getValue();
					}
					i++;
				}
				
				
				//evaluating the expression using JEval
				Evaluator e = new Evaluator();
				String b = e.evaluate(expr);
				
				//JEval returns double so we need to parse the string
				Double d = Double.parseDouble(b);
				symbolTable.insertVariable(promenliva,d.intValue());
				
				//reset the expression variable expr
				expr="";
			}
		}

	}
}
